package com.github.xzb617.utils;

import com.github.xzb617.client.flow.dto.HotParamRule;
import com.github.xzb617.client.route.dto.RouteRule;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class ObjectMapUtil {

    /**
     * 日志
     */
    private final static Logger LOGGER = LoggerFactory.getLogger(ObjectMapUtil.class);
    /**
     * 大写字母正则
     */
    private final static Pattern CAPITAL_PATTERN = Pattern.compile("[A-Z]");

    public static Map<String, Object> objToMap(String prefix, Object object) {
        List<Field> fields = ReflectUtil.getFields(object.getClass());
        Map<String, Object> resMap = new HashMap<>(fields.size());
        try {
            for (Field field : fields) {
                if (field.getType() == Map.class) {
                    String fieldName = field.getName();
                    String propName = convertConfPropName(fieldName, prefix);
                    Map<Object, Object> propValueMap = (Map<Object, Object>) ReflectUtil.getFieldValue(field, object);
                    Set<Map.Entry<Object, Object>> entries = propValueMap.entrySet();
                    for (Map.Entry<Object, Object> entry : entries) {
                        String enKey = String.valueOf(entry.getKey());
                        String key = null;
                        if (enKey.contains("/")) {
                            key = convertConfPropNameWithoutCamel(enKey, propName);
                        } else {
                            key = convertConfPropNameWithoutCamel(enKey, propName);
                        }
                        Object value = entry.getValue();
                        if (value instanceof HotParamRule) {
                            resMap.putAll(objToMap(key, value));
                        }
                        if (value instanceof RouteRule) {
                            resMap.putAll(objToMap(key, value));
                        }
                        else if (value instanceof Map) {
                            Map<Object, Object> map = (Map<Object, Object>) value;
                            resMap.putAll(parseMapValue(map, key));
                        }
                        else {
                            resMap.put(key, value);
                        }
                    }
                }
                else {
                    String fieldName = field.getName();
                    String propName = convertConfPropName(fieldName, prefix);
                    Object propValue = ReflectUtil.getFieldValue(field, object);
                    resMap.put(propName, propValue);
                }
            }
        } catch (IllegalAccessException e) {
            return new HashMap<>(0);
        }
        return resMap;
    }


    private static Map<String, Object> parseMapValue(Map<Object, Object> map, String prefix) {
        Map<String, Object> resMap = new HashMap<>();
        Set<Map.Entry<Object, Object>> entries = map.entrySet();
        for (Map.Entry<Object, Object> entry : entries) {
            String enKey = String.valueOf(entry.getKey());
            String key = null;
            if (enKey.contains("/")) {
                key = convertConfPropNameWithoutCamel(enKey, prefix);
            }
            else if (enKey.contains(".")) {
                key = convertConfPropNameWithoutCamel(enKey, prefix);
            }
            else {
                key = convertConfPropNameWithoutCamel(enKey, prefix);
            }
            Object value = entry.getValue();
            if (value instanceof HotParamRule || value instanceof Map || value instanceof RouteRule) {
                resMap.putAll(objToMap(key, value));
            } else {
                resMap.put(key, value);
            }
        }
        return resMap;
    }

    /**
     * 对象属性名转成配置属性名
     * @param objectFieldName 对象属性名
     * @param prefix 固定前缀
     * @return String
     */
    private static String convertConfPropName(String objectFieldName, String prefix) {
        String fixedPrefix = prefix + ".";
        return fixedPrefix + camelToLine(objectFieldName);
    }

    private static String convertConfPropNameWithoutCamel(String objectFieldName, String prefix) {
        String fixedPrefix = prefix + ".";
        return fixedPrefix + objectFieldName;
    }


    /**
     * 驼峰转换，默认转换成短横线
     * 示例： userName -> user-name
     * @param value 属性值
     * @return String
     */
    private static String camelToLine(String value) {
        Matcher matcher = CAPITAL_PATTERN.matcher(value);
        StringBuffer stringBuffer = new StringBuffer();
        while (matcher.find()) {
            matcher.appendReplacement(stringBuffer, "-" + matcher.group(0).toLowerCase());
        }
        matcher.appendTail(stringBuffer);
        return stringBuffer.toString();
    }

}
